﻿using System.Web.Mvc;
using zeus.Core;
using SharpArch.Web.NHibernate;
using SharpArch.Core;
using SharpArch.Core.PersistenceSupport;
using System.Collections.Generic;
using Webdiyer.WebControls.Mvc;
using System;
using System.Linq;
using zeus.Core.RepositoryInterfaces;
using zeus.Web.Controllers.Helpers;

namespace zeus.Web.Controllers
{
    [HandleError]
    public class RecursosController : Controller
    {

        #region Constructor
        private readonly IUnidadRepository unidadRepository;
        private readonly IRepository<Grupo> grupoRepository;
        private readonly IRepository<Dispositivo> dispositivoRepository;
        private readonly IUsuarioRepository usuarioRepository;
        private readonly IRepository<Cliente> clienteRepository;
        private readonly IRepository<Terminal> terminalRepository;
        private readonly IRepository<Idioma> idiomaRepository;
        private readonly IRepository<Pais> paisRepository;
        private readonly IUsuarioUnidadRepository usuarioUnidadRepository;
        private readonly IEventoRepository eventoRepository;
        private readonly IUnidadEventoRepository unidadEventoRepository;
        private readonly IRepository<Leyenda> leyendaRepository;
        private readonly IGrupoUsuarioRepository grupoUsuarioRepository;
        private readonly IGrupoUnidadRepository grupoUnidadRepository;
        private readonly IRepository<Reporte> reporteRepository;
        private readonly IPoligonoRepository poligonoRepository;
        private readonly IRepository<TimeZoneZeus> timeZoneRepository;
        private readonly IRepository<UsuarioReporte> usuarioReporteRepository;

        public RecursosController(IUnidadRepository unidadesRepository,
            IRepository<TimeZoneZeus> timeZoneRepository,
            IRepository<Grupo> gruposRepository,
            IRepository<Dispositivo> dispositivosRepository,
            IUsuarioRepository usuarioRepository,
            IRepository<Cliente> clientesRepository,
            IRepository<Terminal> terminalesRepository,
            IRepository<Idioma> idiomasRepository,
            IRepository<Pais> paisesRepository,
            IUsuarioUnidadRepository usuarioUnidadRepository,
            IEventoRepository eventoRepository,
            IUnidadEventoRepository unidadEventoRepository,
            IRepository<Leyenda> leyendaRepository,
            IGrupoUsuarioRepository grupoUsuarioRepository,
            IGrupoUnidadRepository grupoUnidadRepository,
            IRepository<Reporte> reporteRepository,
            IPoligonoRepository poligonoRepository,
            IRepository<UsuarioReporte> usuarioReporteRepository)
        {
            Check.Require(usuarioReporteRepository != null, "usuarioReporteRepository may not be null");
            this.usuarioReporteRepository = usuarioReporteRepository;

            Check.Require(timeZoneRepository != null, "timeZoneRepository may not be null");
            this.timeZoneRepository = timeZoneRepository;

            Check.Require(poligonoRepository != null, "poligonoRepository may not be null");
            this.poligonoRepository = poligonoRepository;

            Check.Require(reporteRepository != null, "reporteRepository may not be null");
            this.reporteRepository = reporteRepository;

            Check.Require(grupoUsuarioRepository != null, "grupoUsuarioRepository may not be null");
            this.grupoUsuarioRepository = grupoUsuarioRepository;

            Check.Require(grupoUnidadRepository != null, "grupoUnidadRepository may not be null");
            this.grupoUnidadRepository = grupoUnidadRepository;

            Check.Require(leyendaRepository != null, "leyendaRepository may not be null");
            this.leyendaRepository = leyendaRepository;

            Check.Require(unidadEventoRepository != null, "unidadEventoRepository may not be null");
            this.unidadEventoRepository = unidadEventoRepository;

            Check.Require(eventoRepository != null, "eventoRepository may not be null");
            this.eventoRepository = eventoRepository;

            Check.Require(usuarioUnidadRepository != null, "usuarioUnidadRepository may not be null");
            this.usuarioUnidadRepository = usuarioUnidadRepository;

            Check.Require(unidadesRepository != null, "unidadesRepository may not be null");
            this.unidadRepository = unidadesRepository;

            Check.Require(gruposRepository != null, "gruposRepository may not be null");
            this.grupoRepository = gruposRepository;

            Check.Require(dispositivosRepository != null, "dispositivosRepository may not be null");
            this.dispositivoRepository = dispositivosRepository;

            Check.Require(usuarioRepository != null, "dispositivosRepository may not be null");
            this.usuarioRepository = usuarioRepository;

            Check.Require(clientesRepository != null, "clientesRepository may not be null");
            this.clienteRepository = clientesRepository;

            Check.Require(terminalesRepository != null, "terminalesRepository may not be null");
            this.terminalRepository = terminalesRepository;

            Check.Require(idiomasRepository != null, "idiomasRepository may not be null");
            this.idiomaRepository = idiomasRepository;

            Check.Require(paisesRepository != null, "paisesRepository may not be null");
            this.paisRepository = paisesRepository;
        }

        public WorkingSession workingSession
        {
            get
            {
                if (Session["WorkingSession"] == null)
                    throw new SessionExpiredException();
                return Session["WorkingSession"] as WorkingSession;
            }
            set
            {
                Session["WorkingSession"] = value;
            }
        }
        #endregion

        public ActionResult Index()
        {
            return View();
        }


        #region Leyendas

        /// <summary>
        /// Recupera todas las leyendas y las asocia al evento que se esta editando
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [Transaction, Authorize]
        public ActionResult Leyendas(int? id)
        {
            // Determinar si tiene autorización
            if (!usuarioRepository.IsInRole(User.Identity.Name, "admin,cliente"))
                return RedirectToAction("NoAutorizado", "Shared");

            try
            {
                if (TempData["unidadId"] != null)
                    id = (int)TempData["unidadId"];

                Unidad unidad = unidadRepository.Get(id.Value);
                Check.Require(unidad != null, "No se pudo recuperar la Unidad");

                IList<Evento> eventos = eventoRepository.GetAll();

                foreach (var evento in eventos)
                {
                    bool encontro = false;

                    foreach (var leyenda in unidad.Leyendas)
                    {
                        if (leyenda.Evento.Id == evento.Id)
                            encontro = true;
                    }

                    if (!encontro)
                    {
                        unidad.AddLeyenda(new Leyenda()
                        {
                            Evento = evento,
                            Nombre = evento.Nombre,
                            CodigoEvento = evento.Id,
                            CodigoUnidad = unidad.Id
                        });
                    }
                }

                unidadRepository.SaveOrUpdate(unidad);

                return View(unidad.Leyendas.OrderBy(p => p.Nombre).ToList());
            }
            catch (PreconditionException ex)
            {
                TempData["ErrorMessage"] = ex.Message;
                return RedirectToAction("Error", "Shared");
            }
            catch (SessionExpiredException)
            {
                TempData["ErrorMessage"] = "Sesión Expirada!";
                TempData["Expire"] = true;
                return RedirectToAction("Error", "Shared");
            }
            catch (Exception ex)
            {
                TempData["ErrorMessage"] = ex.Message;
                return RedirectToAction("Error", "Shared");
            }

        }

        /// <summary>
        /// Metodo GET para las leyendas
        /// </summary>
        /// <param name="eventoId"></param>
        /// <param name="unidadId"></param>
        /// <returns></returns>
        [Transaction, Authorize]
        public ActionResult EditarLeyenda(int eventoId, int unidadId)
        {
            // Determinar si tiene autorización
            if (!usuarioRepository.IsInRole(User.Identity.Name, "admin,cliente"))
                return RedirectToAction("NoAutorizado", "Shared");

            try
            {
                Dictionary<string, object> filtro = new Dictionary<string, object>();
                filtro.Add("Unidad.Id", unidadId);
                filtro.Add("Evento.Id", eventoId);

                Leyenda leyenda = leyendaRepository.FindAll(filtro).FirstOrDefault();
                Check.Require(leyenda != null, "La leyenda no pudo ser recuperada");

                return View(leyenda);
            }
            catch (PreconditionException ex)
            {
                TempData["ErrorMessage"] = ex.Message;
                return RedirectToAction("Error", "Shared");
            }
            catch (SessionExpiredException)
            {
                TempData["ErrorMessage"] = "Sesión Expirada!";
                TempData["Expire"] = true;
                return RedirectToAction("Error", "Shared");
            }
            catch (Exception ex)
            {
                TempData["ErrorMessage"] = ex.Message;
                return RedirectToAction("Error", "Shared");
            }
        }

        /// <summary>
        /// Metodo POST para editar las leyendas
        /// </summary>
        /// <param name="leyenda"></param>
        /// <returns></returns>
        [Transaction, HttpPost, Authorize]
        public ActionResult EditarLeyenda(Leyenda leyenda)
        {
            // Determinar si tiene autorización
            if (!usuarioRepository.IsInRole(User.Identity.Name, "admin,cliente"))
                return RedirectToAction("NoAutorizado", "Shared");

            try
            {
                if (ModelState.IsValid && leyenda.IsValid())
                {
                    Dictionary<string, object> filtro = new Dictionary<string, object>();
                    filtro.Add("Unidad.Id", leyenda.CodigoUnidad);
                    filtro.Add("Evento.Id", leyenda.CodigoEvento);

                    Leyenda leyendaUpdated = leyendaRepository.FindAll(filtro).FirstOrDefault();
                    UpdateModel(leyendaUpdated);
                    leyendaRepository.SaveOrUpdate(leyendaUpdated);

                    TempData["unidadId"] = leyenda.CodigoUnidad;
                    return RedirectToAction("Leyendas");
                }

                return View(leyenda);
            }
            catch (PreconditionException ex)
            {
                TempData["ErrorMessage"] = ex.Message;
                return RedirectToAction("Error", "Shared");
            }
            catch (SessionExpiredException)
            {
                TempData["ErrorMessage"] = "Sesión Expirada!";
                TempData["Expire"] = true;
                return RedirectToAction("Error", "Shared");
            }
            catch (Exception ex)
            {
                TempData["ErrorMessage"] = ex.Message;
                return RedirectToAction("Error", "Shared");
            }
        }
        #endregion

        #region Unidades
        /// <summary>
        /// Listado de unidades
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [Transaction, Authorize]
        public ActionResult Unidades(int? id, int? clienteId, string buscar)
        {
            // Determinar si tiene autorización
            if (!usuarioRepository.IsInRole(User.Identity.Name, "admin,cliente"))
                return RedirectToAction("NoAutorizado", "Shared");

            try
            {
                IList<Cliente> clientes = clienteRepository.GetAll();
                ViewData["Clientes"] = new SelectList(clientes, "Id", "Nombre", clienteId);

                IList<Unidad> unidades = new List<Unidad>();


                int codigoCliente = 0;

                if (usuarioRepository.IsInRole(User.Identity.Name, "admin"))
                {
                    codigoCliente = clienteId ?? clientes[0].Id;

                    ViewData["ClienteId"] = clienteId ?? clientes[0].Id;
                    ViewData["IsAdmin"] = true;
                }
                else
                {
                    codigoCliente = workingSession.Usuario.CodigoCliente;

                    ViewData["ClienteId"] = workingSession.Usuario.CodigoCliente;
                    ViewData["IsAdmin"] = false;
                }



                if (!string.IsNullOrEmpty(buscar))
                    unidades = unidadRepository.GetByNombre(buscar, codigoCliente);
                else
                    unidades = unidadRepository.GetByCliente(codigoCliente);
                // unidades = unidadRepository.GetByClienteUbicacion();

                ViewData["txtBuscar"] = buscar;

                //unidades.ToList().ForEach(p => p.Ubicaciones.OrderByDescending(q => q.Fecha).FirstOrDefault());

                PagedList<Unidad> unidadesList = new PagedList<Unidad>(unidades, id ?? 1, 10);

                return View(unidadesList);



            }
            catch (PreconditionException ex)
            {
                TempData["ErrorMessage"] = ex.Message;
                return RedirectToAction("Error", "Shared");
            }
            catch (SessionExpiredException)
            {
                TempData["ErrorMessage"] = "Sesión Expirada!";
                TempData["Expire"] = true;
                return RedirectToAction("Error", "Shared");
            }
            catch (Exception ex)
            {
                TempData["ErrorMessage"] = ex.Message;
                return RedirectToAction("Error", "Shared");
            }

        }

        [Transaction, Authorize]
        public ActionResult UnidadesDetallada(int? id, int? clienteId, string buscar)
        {
            // Determinar si tiene autorización
            if (!usuarioRepository.IsInRole(User.Identity.Name, "admin,cliente"))
                return RedirectToAction("NoAutorizado", "Shared");

            try
            {
                IList<Cliente> clientes = clienteRepository.GetAll();
                ViewData["Clientes"] = new SelectList(clientes, "Id", "Nombre", clienteId);

                IList<Unidad> unidades = new List<Unidad>();
                int codigoCliente = 0;

                if (usuarioRepository.IsInRole(User.Identity.Name, "admin"))
                {
                    codigoCliente = clienteId ?? clientes[0].Id;
                    ViewData["ClienteId"] = clienteId ?? clientes[0].Id;
                    ViewData["IsAdmin"] = true;
                }
                else
                {
                    codigoCliente = workingSession.Usuario.CodigoCliente;
                    ViewData["ClienteId"] = workingSession.Usuario.CodigoCliente;
                    ViewData["IsAdmin"] = false;
                }

                if (!string.IsNullOrEmpty(buscar))
                    unidades = unidadRepository.GetByNombre(buscar, codigoCliente);
                else
                    unidades = unidadRepository.GetByCliente(codigoCliente);
                // unidades = unidadRepository.GetByClienteUbicacion();

                ViewData["txtBuscar"] = buscar;

                PagedList<Unidad> unidadesList = new PagedList<Unidad>(unidades, id ?? 1, 10);
                return View(unidadesList);
            }
            catch (PreconditionException ex)
            {
                TempData["ErrorMessage"] = ex.Message;
                return RedirectToAction("Error", "Shared");
            }
            catch (SessionExpiredException)
            {
                TempData["ErrorMessage"] = "Sesión Expirada!";
                TempData["Expire"] = true;
                return RedirectToAction("Error", "Shared");
            }
            catch (Exception ex)
            {
                TempData["ErrorMessage"] = ex.Message;
                return RedirectToAction("Error", "Shared");
            }

        }

        /// <summary>
        /// Get Method.
        /// Obtener el detalle de la unidad
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [Transaction, Authorize]
        public ActionResult NuevaUnidad(int? id, int? clienteId)
        {            
            try
            {
                // Determinar si tiene autorización
                if (!usuarioRepository.IsInRole(User.Identity.Name, "admin,cliente"))
                    return RedirectToAction("NoAutorizado", "Shared");
                
                // Determinar si el usuario tiene autorización a cambiar el número de celular
                if (usuarioRepository.TieneReporte(workingSession.Usuario, 16))
                    ViewData["CambiarCelular"] = true;
                else
                    ViewData["CambiarCelular"] = false;

                Unidad unidad = new Unidad();
                if (id != null)
                {
                    unidad = unidadRepository.Get(id.Value);
                    Check.Require(unidad != null, "La unidad no pudo ser recuperada");

                    // Validar ingresos no permitidos
                    if (!workingSession.Usuario.Rol.Equals("admin"))
                        Check.Require(workingSession.Usuario.CodigoCliente == unidad.CodigoCliente, 
                            "No tiene autorización para acceder a la unidad");                    
                }
                else
                {
                    unidad.CodigoCliente = clienteId ?? workingSession.Usuario.CodigoCliente;
                }

                InicializarCombosUnidad(unidad, clienteId == null ? unidad.CodigoCliente : clienteId);

                return View(unidad);
            }
            catch (PreconditionException ex)
            {
                TempData["ErrorMessage"] = ex.Message;
                return RedirectToAction("Error", "Shared");
            }
            catch (SessionExpiredException)
            {
                TempData["ErrorMessage"] = "Sesión Expirada!";
                TempData["Expire"] = true;
                return RedirectToAction("Error", "Shared");
            }
            catch (Exception ex)
            {
                TempData["ErrorMessage"] = ex.Message;
                return RedirectToAction("Error", "Shared");
            }
        }

        /// <summary>
        /// Post Method.
        /// Guardar los cambios de la unidad.        
        /// </summary>
        /// <param name="Id"></param>
        /// <param name="unidad"></param>
        /// <returns></returns>
        [Transaction, HttpPost, Authorize]
        public ActionResult NuevaUnidad(int? Id, Unidad unidad)
        {
            // Determinar si tiene autorización
            if (!usuarioRepository.IsInRole(User.Identity.Name, "admin,cliente"))
                return RedirectToAction("NoAutorizado", "Shared");

            try
            {
                bool error = false;

                // Validaciones adicionales
                if (string.IsNullOrEmpty(unidad.UsuariosHidden))
                {
                    error = true;
                    ModelState.AddModelError("UsuarioUnidades", "Debe seleccionar al menos un usuario.");
                }


                if (ModelState.IsValid && unidad.IsValid() && error == false)
                {
                    Unidad unidadUpdated = unidad;

                    if (Id != null)
                    {
                        unidadUpdated = unidadRepository.Get(Id.Value);
                        Check.Require(unidadUpdated != null, "La unidad no pudo ser recuperada");
                        UpdateModel(unidadUpdated);
                    }                    

                    #region Agregar Usuarios
                    string[] selectedUsuarios = unidad.UsuariosHidden.Split(',');

                    // Eliminar todos los usuarios
                    usuarioUnidadRepository.DeleteAll(unidadUpdated);

                    // Insertar usuarios seleccionados
                    foreach (var item in selectedUsuarios)
                    {
                        UsuarioUnidad usuarioUnidad = new UsuarioUnidad()
                        {
                            Usuario = usuarioRepository.Get(Convert.ToInt32(item))
                        };

                        unidadUpdated.AddUsuario(usuarioUnidad);
                    }
                    #endregion

                    #region Agregar Eventos

                    // Eliminar todos los eventos
                    unidadEventoRepository.DeleteAll(unidadUpdated);

                    if (!string.IsNullOrEmpty(unidad.EventosHidden))
                    {
                        string[] eventosSelected = unidad.EventosHidden.Split(',');

                        // Insertar eventos seleccionados
                        foreach (var item in eventosSelected)
                        {
                            UnidadEvento unidadEvento = new UnidadEvento()
                            {
                                Evento = eventoRepository.Get(Convert.ToInt32(item))
                            };

                            unidadUpdated.AddEvento(unidadEvento);
                        }
                    }
                    #endregion

                    unidadRepository.SaveOrUpdate(unidadUpdated);

                    return RedirectToAction("Unidades");
                }

                InicializarCombosUnidad(unidad, unidad.CodigoCliente);
                return View(unidad);
            }
            catch (PreconditionException ex)
            {
                TempData["ErrorMessage"] = ex.Message;
                return RedirectToAction("Error", "Shared");
            }
            catch (SessionExpiredException)
            {
                TempData["ErrorMessage"] = "Sesión Expirada!";
                TempData["Expire"] = true;
                return RedirectToAction("Error", "Shared");
            }
            catch (Exception ex)
            {
                TempData["ErrorMessage"] = ex.Message;
                return RedirectToAction("Error", "Shared");
            }
        }

        /// <summary>
        /// Eliminar unidad. Llamada via AJAX
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [Transaction, HttpPost, Authorize]
        public ActionResult EliminarUnidad(int id)
        {
            // Determinar si tiene autorización
            if (!usuarioRepository.IsInRole(User.Identity.Name, "admin,cliente"))
                return RedirectToAction("NoAutorizado", "Shared");

            try
            {
                Unidad unidad = unidadRepository.Get(id);
                Check.Require(unidad != null, "La unidad no pudo ser recuperada");
                unidadRepository.Delete(unidad);
                unidadRepository.DbContext.CommitTransaction();
                return Json("");
            }
            catch (PreconditionException)
            {
                return Json("Ha ocurrido un error en la aplicación. Por favor intente más tarde.");
            }
            catch (Exception ex)
            {
                return Json("El registro no pudo ser eliminado, posiblemente tenga relación con otra entidad." + ex.Message);
            }
        }

        /// <summary>
        /// Inicializar combos de unidad
        /// </summary>
        /// <param name="unidad"></param> 
        private void InicializarCombosUnidad(Unidad unidad, int? clienteId)
        {
            IList<Terminal> CodigoTerminal = terminalRepository.GetAll();
            ViewData["CodigoTerminal"] = new SelectList(CodigoTerminal, "Id", "Nombre", unidad.CodigoTerminal);

            IList<Dispositivo> CodigoDispositivo = dispositivoRepository.GetAll();
            ViewData["CodigoDispositivo"] = new SelectList(CodigoDispositivo, "Id", "Nombre", unidad.CodigoDispositivo);

            IList<Dispositivo> CodigoMarcaDispositivo = dispositivoRepository.GetAll();
            ViewData["CodigoMarcaDispositivo"] = new SelectList(CodigoMarcaDispositivo, "Id", "Marca", unidad.CodigoDispositivo);

            IList<Idioma> CodigoIdioma = idiomaRepository.GetAll();
            ViewData["CodigoIdioma"] = new SelectList(CodigoIdioma, "Id", "Nombre", unidad.CodigoIdioma);

            IList<Usuario> usuariosDisponibles = usuarioRepository.GetDisponiblesByUnidad(clienteId ?? workingSession.Usuario.CodigoCliente, unidad);
            IList<Usuario> usuariosSeleccionados = usuarioRepository.GetSeleccionadosByUnidad(clienteId ?? workingSession.Usuario.CodigoCliente, unidad);
            ViewData["UsuariosDisponibles"] = new MultiSelectList(usuariosDisponibles, "Id", "Nombre");
            ViewData["UsuariosSeleccionados"] = new MultiSelectList(usuariosSeleccionados, "Id", "Nombre");

            IList<Evento> eventosDisponibles = eventoRepository.GetDisponiblesByUnidad(unidad);
            IList<Evento> eventosSeleccionados = eventoRepository.GetSeleccionadosByUnidad(unidad);
            ViewData["EventosDisponibles"] = new MultiSelectList(eventosDisponibles, "Id", "Nombre");
            ViewData["EventosSeleccionados"] = new MultiSelectList(eventosSeleccionados, "Id", "Nombre");

            List<SelectListItem> velocidad = new List<SelectListItem>()
            {
                new SelectListItem { Value = "1", Text = "Kph" },
                new SelectListItem { Value = "2", Text = "Mph" }
            };

            ViewData["Velocidad"] = new SelectList(velocidad, "Value", "Text", unidad.Velocidad);

            List<SelectListItem> icono = new List<SelectListItem>() 
                { 
                    new SelectListItem { Value = "icon_carf0", Text="Auto" },
                    new SelectListItem { Value = "icon_carf4", Text="Bus" },
                    new SelectListItem { Value = "icon_carf6", Text="Motocicleta" },
                    new SelectListItem { Value = "icon_carf12", Text="Personal" }
                };

            ViewData["Icono"] = new SelectList(icono, "Value", "Text", unidad.Icono);
        }
        #endregion

        #region Grupos

        /// <summary>
        /// Recupera todo los grupos que pertenecen al cliente
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [Transaction, Authorize]
        public ActionResult Grupos(int? id, int? clienteId, string buscar)
        {
            if (!usuarioRepository.IsInRole(User.Identity.Name, "admin,cliente"))
                return RedirectToAction("NoAutorizado", "Shared");
            try
            {
                IList<Cliente> clientes = clienteRepository.GetAll();
                ViewData["Clientes"] = new SelectList(clientes, "Id", "Nombre", clienteId);

                Dictionary<string, object> filtro = new Dictionary<string, object>();

                if (usuarioRepository.IsInRole(User.Identity.Name, "admin"))
                {
                    filtro.Add("CodigoCliente", clienteId ?? clientes[0].Id);
                    ViewData["ClienteId"] = clienteId ?? clientes[0].Id;
                    ViewData["IsAdmin"] = true;
                }
                else
                {
                    filtro.Add("CodigoCliente", workingSession.Usuario.CodigoCliente);
                    ViewData["ClienteId"] = workingSession.Usuario.CodigoCliente;
                    ViewData["IsAdmin"] = false;
                }

                //IList<Grupo> grupos = grupoRepository.FindAll(filtro);
                //grupos = grupoRepository.FindAll(filtro);
                IList<Grupo> grupos = new List<Grupo>();

                if (!string.IsNullOrEmpty(buscar))
                   // unidades = unidadRepository.GetByNombre(buscar, clienteId);
                    grupos = grupoUsuarioRepository.GetByCliente(clienteId ?? clientes[0].Id);
                else
                    grupos = grupoUsuarioRepository.GetByCliente(clienteId ?? clientes[0].Id);

                // unidades = unidadRepository.GetByClienteUbicacion();

                ViewData["txtBuscar"] = buscar;



               

                

                PagedList<Grupo> gruposList = new PagedList<Grupo>(grupos, id ?? 1, 10);
                return View(gruposList);
            }
            catch (PreconditionException ex)
            {
                TempData["ErrorMessage"] = ex.Message;
                return RedirectToAction("Error", "Shared");
            }
            catch (SessionExpiredException)
            {
                TempData["ErrorMessage"] = "Sesión Expirada!";
                TempData["Expire"] = true;
                return RedirectToAction("Error", "Shared");
            }
            catch (Exception ex)
            {
                TempData["ErrorMessage"] = ex.Message;
                return RedirectToAction("Error", "Shared");
            }

        }


        [Transaction, Authorize]
        public ActionResult GruposDetallada(int? id, int? clienteId, string buscar)
        {
            if (!usuarioRepository.IsInRole(User.Identity.Name, "admin,cliente"))
                return RedirectToAction("NoAutorizado", "Shared");
            try
            {
                IList<Cliente> clientes = clienteRepository.GetAll();
                ViewData["Clientes"] = new SelectList(clientes, "Id", "Nombre", clienteId);

                Dictionary<string, object> filtro = new Dictionary<string, object>();

                if (usuarioRepository.IsInRole(User.Identity.Name, "admin"))
                {
                    filtro.Add("CodigoCliente", clienteId ?? clientes[0].Id);
                    ViewData["ClienteId"] = clienteId ?? clientes[0].Id;
                    ViewData["IsAdmin"] = true;
                }
                else
                {
                    filtro.Add("CodigoCliente", workingSession.Usuario.CodigoCliente);
                    ViewData["ClienteId"] = workingSession.Usuario.CodigoCliente;
                    ViewData["IsAdmin"] = false;
                }

                //IList<Grupo> grupos = grupoRepository.FindAll(filtro);
                //grupos = grupoRepository.FindAll(filtro);
                IList<Grupo> grupos = new List<Grupo>();

                if (!string.IsNullOrEmpty(buscar))
                    // unidades = unidadRepository.GetByNombre(buscar, clienteId);
                    grupos = grupoUsuarioRepository.GetByCliente(clienteId ?? clientes[0].Id);
                else
                    grupos = grupoUsuarioRepository.GetByCliente(clienteId ?? clientes[0].Id);

                // unidades = unidadRepository.GetByClienteUbicacion();

                ViewData["txtBuscar"] = buscar;







                PagedList<Grupo> gruposList = new PagedList<Grupo>(grupos, id ?? 1, 10);
                return View(gruposList);
            }
            catch (PreconditionException ex)
            {
                TempData["ErrorMessage"] = ex.Message;
                return RedirectToAction("Error", "Shared");
            }
            catch (SessionExpiredException)
            {
                TempData["ErrorMessage"] = "Sesión Expirada!";
                TempData["Expire"] = true;
                return RedirectToAction("Error", "Shared");
            }
            catch (Exception ex)
            {
                TempData["ErrorMessage"] = ex.Message;
                return RedirectToAction("Error", "Shared");
            }

        }
        /// <summary>
        /// Metodo GET para crear o editar un grupo
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [Transaction, Authorize]
        public ActionResult NuevoGrupo(int? id, int? clienteId)
        {
            // Determinar si tiene autorización
            if (!usuarioRepository.IsInRole(User.Identity.Name, "admin,cliente"))
                return RedirectToAction("NoAutorizado", "Shared");

            try
            {
                Grupo grupo = new Grupo();
                if (id != null)
                {
                    grupo = grupoRepository.Get(id.Value);

                    // Validar ingresos no permitidos
                    if (!workingSession.Usuario.Rol.Equals("admin"))
                        Check.Require(grupo.CodigoCliente == workingSession.Usuario.CodigoCliente,
                            "No tiene autorización para acceder al grupo"); 
                }
                else
                {
                    grupo.CodigoCliente = clienteId ?? workingSession.Usuario.CodigoCliente;
                }

                InicializarCombosGrupo(grupo, clienteId == null ? grupo.CodigoCliente : clienteId);

                return View(grupo);
            }
            catch (PreconditionException ex)
            {
                TempData["ErrorMessage"] = ex.Message;
                return RedirectToAction("Error", "Shared");
            }
            catch (SessionExpiredException)
            {
                TempData["ErrorMessage"] = "Sesión Expirada!";
                TempData["Expire"] = true;
                return RedirectToAction("Error", "Shared");
            }
            catch (Exception ex)
            {
                TempData["ErrorMessage"] = ex.Message;
                return RedirectToAction("Error", "Shared");
            }
        }

        /// <summary>
        /// Metodo POST para crear o editar un grupo
        /// </summary>
        /// <param name="Id"></param>
        /// <param name="grupo"></param>
        /// <returns></returns>
        [Transaction, HttpPost, Authorize]
        public ActionResult NuevoGrupo(int? Id, Grupo grupo)
        {
            if (!usuarioRepository.IsInRole(User.Identity.Name, "admin,cliente"))
                return RedirectToAction("NoAutorizado", "Shared");

            try
            {

                if (ModelState.IsValid && grupo.IsValid())
                {
                    Grupo grupoUpdated = grupo;

                    if (Id != null)
                    {
                        grupoUpdated = grupoRepository.Get(Id.Value);
                        UpdateModel(grupoUpdated);
                    }                    

                    #region Agregar Usuarios

                    // Eliminar todos los usuarios
                    grupoUsuarioRepository.DeleteAll(grupoUpdated);

                    if (!string.IsNullOrEmpty(grupo.UsuariosHidden))
                    {
                        string[] selectedUsuarios = grupo.UsuariosHidden.Split(',');

                        // Insertar usuarios seleccionados
                        foreach (var item in selectedUsuarios)
                        {
                            GrupoUsuario grupoUsuario = new GrupoUsuario()
                            {
                                Usuario = usuarioRepository.Get(Convert.ToInt32(item))
                            };

                            grupoUpdated.AddUsuario(grupoUsuario);
                        }
                    }
                    #endregion

                    #region Agregar Unidades

                    // Eliminar todos los eventos
                    grupoUnidadRepository.DeleteAll(grupoUpdated);

                    if (!string.IsNullOrEmpty(grupo.UnidadesHidden))
                    {
                        string[] eventosSelected = grupo.UnidadesHidden.Split(',');

                        // Insertar eventos seleccionados
                        foreach (var item in eventosSelected)
                        {
                            GrupoUnidad grupoUnidad = new GrupoUnidad()
                            {
                                Unidad = unidadRepository.Get(Convert.ToInt32(item))
                            };

                            grupoUpdated.AddUnidad(grupoUnidad);
                        }
                    }
                    #endregion

                    grupoRepository.SaveOrUpdate(grupoUpdated);

                    return RedirectToAction("Grupos");
                }

                InicializarCombosGrupo(grupo, grupo.CodigoCliente);
                return View(grupo);
            }
            catch (PreconditionException ex)
            {
                TempData["ErrorMessage"] = ex.Message;
                return RedirectToAction("Error", "Shared");
            }
            catch (SessionExpiredException)
            {
                TempData["ErrorMessage"] = "Sesión Expirada!";
                TempData["Expire"] = true;
                return RedirectToAction("Error", "Shared");
            }
            catch (Exception ex)
            {
                TempData["ErrorMessage"] = ex.Message;
                return RedirectToAction("Error", "Shared");
            }
        }

        /// <summary>
        /// Eliminar un Grupo. Invocado mediante AJAX
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [Transaction, HttpPost, Authorize]
        public ActionResult EliminarGrupo(int id)
        {
            if (!usuarioRepository.IsInRole(User.Identity.Name, "admin,cliente"))
                return RedirectToAction("NoAutorizado", "Shared");

            try
            {
                Grupo grupo = grupoRepository.Get(id);
                grupoRepository.Delete(grupo);
                dispositivoRepository.DbContext.CommitTransaction();
                return Json("");
            }
            catch (PreconditionException)
            {
                return Json("Ha ocurrido un error en la aplicación. Por favor intente más tarde.");
            }
            catch (Exception)
            {
                return Json("El registro no pudo ser eliminado, posiblemente tenga relación con otra entidad.");
            }
        }

        /// <summary>
        /// Inicializar combos para grupos.
        /// </summary>
        /// <param name="grupo"></param>
        /// <param name="clienteId"></param>
        private void InicializarCombosGrupo(Grupo grupo, int? clienteId)
        {            
            IList<Usuario> usuariosDisponibles = usuarioRepository.GetDisponiblesByGrupo(clienteId ?? workingSession.Usuario.CodigoCliente, grupo);
            IList<Usuario> usuariosSeleccionados = usuarioRepository.GetSeleccionadosByGrupo(clienteId ?? workingSession.Usuario.CodigoCliente, grupo);
            ViewData["UsuariosDisponibles"] = new MultiSelectList(usuariosDisponibles, "Id", "Nombre");
            ViewData["UsuariosSeleccionados"] = new MultiSelectList(usuariosSeleccionados, "Id", "Nombre");

            IList<Unidad> unidadesDisponibles = unidadRepository.GetDisponiblesByGrupo(clienteId ?? workingSession.Usuario.CodigoCliente, grupo);
            IList<Unidad> unidadesSeleccionados = unidadRepository.GetSeleccionadosByGrupo(clienteId ?? workingSession.Usuario.CodigoCliente, grupo);
            ViewData["UnidadesDisponibles"] = new MultiSelectList(unidadesDisponibles, "Id", "Nombre");
            ViewData["UnidadesSeleccionados"] = new MultiSelectList(unidadesSeleccionados, "Id", "Nombre");

        }


        #endregion

        #region Usuarios

        /// <summary>
        /// Lista de usuarios disponibles para un cliente
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [Transaction, Authorize]
        public ActionResult Usuarios(int? id, int? clienteId)
        { 
            try
            {
                // Validar que tenga permisos el usuario.
                if (!usuarioRepository.TieneReporte(workingSession.Usuario, 2))
                    return RedirectToAction("NoAutorizado", "Shared");

                Dictionary<string, object> filtro = new Dictionary<string, object>();
                
                // Recuperar todos los clientes
                IList<Cliente> clientes = clienteRepository.GetAll();
                ViewData["Clientes"] = new SelectList(clientes, "Id", "Nombre", clienteId);

                filtro.Clear();

                // Determinar si el usuario es administrador
                if (usuarioRepository.IsInRole(User.Identity.Name, "admin"))
                {
                    filtro.Add("CodigoCliente", clienteId ?? clientes[0].Id);
                    ViewData["ClienteId"] = clienteId ?? clientes[0].Id;
                    ViewData["Rol"] = "admin";
                }
                else
                {
                    filtro.Add("CodigoCliente", workingSession.Usuario.CodigoCliente);
                    ViewData["ClienteId"] = workingSession.Usuario.CodigoCliente;
                    ViewData["Rol"] = "cliente";
                }

                // Validar permisos cuando es Rol USUARIO.
                if (usuarioRepository.IsInRole(User.Identity.Name, "usuario"))
                {
                    filtro.Add("Id", workingSession.Usuario.Id);
                    ViewData["Rol"] = "usuario";
                }
                    
                IList<Usuario> usuario = usuarioRepository.FindAll(filtro);
                PagedList<Usuario> usuarios = new PagedList<Usuario>(usuario, id ?? 1, 10);
                
                return View(usuarios);
            }
            catch (PreconditionException ex)
            {
                TempData["ErrorMessage"] = ex.Message;
                return RedirectToAction("Error", "Shared");
            }
            catch (SessionExpiredException)
            {
                TempData["ErrorMessage"] = "Sesión Expirada!";
                TempData["Expire"] = true;
                return RedirectToAction("Error", "Shared");
            }
            catch (Exception ex)
            {
                TempData["ErrorMessage"] = ex.Message;
                return RedirectToAction("Error", "Shared");
            }

        }

        /// <summary>
        /// Metodo GET para editar o crear un usuario.
        /// Agrego los Reportes al usuario.
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [Transaction, Authorize]
        public ActionResult NuevoUsuario(int? id, int? clienteId)
        {
            try
            {
                // Validar que tenga permisos el usuario.
                if (!usuarioRepository.TieneReporte(workingSession.Usuario, 2))
                    return RedirectToAction("NoAutorizado", "Shared");

                // Validar permisos cuando es Rol USUARIO.
                if (usuarioRepository.IsInRole(User.Identity.Name, "usuario"))
                {
                    ViewData["RolUsuario"] = "usuario";
                    Check.Require(workingSession.Usuario.Id == id, "No tiene autorización para editar el usuario.");
                }
                else
                {
                    ViewData["RolUsuario"] = "cliente";
                }

                Usuario usuario = new Usuario();
                if (id != null)
                {
                    usuario = usuarioRepository.Get(id.Value);
                }
                else
                {
                    usuario.CodigoCliente = clienteId ?? workingSession.Usuario.CodigoCliente;
                    usuario.Activo = true;
                }

                // Recuperar reportes disponibles para el usuario
                Dictionary<string, object> filtro = new Dictionary<string, object>();
                filtro.Add("Activo", true);

                IList<Reporte> reportes = reporteRepository.FindAll(filtro);

                // Recupero los reportes del Usuario
                IList<Reporte> reportesUsuario = new List<Reporte>();
                usuario.UsuarioReportes.ToList().ForEach(p => reportesUsuario.Add(p.Reporte));

                foreach (var item in reportes)                
                    if (!reportesUsuario.Contains(item))                    
                        usuario.AddReporte(new UsuarioReporte()
                        {
                            Reporte = item,
                            Estado = true
                        });
                

                InicializarCombosUsuario(usuario);

                return View(usuario);
            }
            catch (PreconditionException ex)
            {
                TempData["ErrorMessage"] = ex.Message;
                return RedirectToAction("Error", "Shared");
            }
            catch (SessionExpiredException)
            {
                TempData["ErrorMessage"] = "Sesión Expirada!";
                TempData["Expire"] = true;
                return RedirectToAction("Error", "Shared");
            }
            catch (Exception ex)
            {
                TempData["ErrorMessage"] = ex.Message;
                return RedirectToAction("Error", "Shared");
            }
        }

        /// <summary>
        /// Metodo POST para crear o editar usuarios.
        /// Valida que el Login no este repetido.
        /// </summary>
        /// <param name="Id"></param>
        /// <param name="usuario"></param>
        /// <param name="form"></param>
        /// <returns></returns>
        [Transaction, HttpPost, Authorize]
        public ActionResult NuevoUsuario(int? Id, Usuario usuario, FormCollection form)
        {

            if (!usuarioRepository.IsInRole(User.Identity.Name, "admin,cliente"))
                return RedirectToAction("NoAutorizado", "Shared");

            try
            {
                bool error = false;

                //No debe existir logins repetidos
                if (usuarioRepository.UsuarioDuplicado(usuario))
                {
                    error = true;
                    ModelState.AddModelError("Login", "El usuario seleccionado ya existe.");
                }

                if (ModelState.IsValid && usuario.IsValid() && !error)
                {
                    Usuario usuarioUpdated = usuario;

                    if (Id != null)
                    {
                        usuarioUpdated = usuarioRepository.Get(Id.Value);
                        UpdateModel(usuarioUpdated);
                    }                    

                    Dictionary<string, object> filtro = new Dictionary<string, object>();
                    filtro.Add("Activo", true);
                    IList<Reporte> reportes = reporteRepository.FindAll(filtro);

                    // Actualizar los estados de acceso a los reportes
                    foreach (var item in reportes)
                    {
                        bool seleccionado = form[item.Id.ToString()].Contains("true");
                        usuarioRepository.InsertOrUpdateReporte(usuarioUpdated, item.Id, seleccionado);
                    }

                    usuarioRepository.SaveOrUpdate(usuarioUpdated);

                    return RedirectToAction("Usuarios");
                }

                InicializarCombosUsuario(usuario);
                return View(usuario);
            }
            catch (PreconditionException ex)
            {
                TempData["ErrorMessage"] = ex.Message;
                return RedirectToAction("Error", "Shared");
            }
            catch (SessionExpiredException)
            {
                TempData["ErrorMessage"] = "Sesión Expirada!";
                TempData["Expire"] = true;
                return RedirectToAction("Error", "Shared");
            }
            catch (Exception ex)
            {
                TempData["ErrorMessage"] = ex.Message;
                return RedirectToAction("Error", "Shared");
            }
        }

        /// <summary>
        /// Eliminar Usuario. Llamada AJAX
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [Transaction, HttpPost, Authorize]
        public ActionResult BorrarUsuario(int id)
        {
            if (!usuarioRepository.IsInRole(User.Identity.Name, "admin,cliente"))
                return RedirectToAction("NoAutorizado", "Shared");

            try
            {
                Usuario usuario = usuarioRepository.Get(id);
                usuarioRepository.Delete(usuario);
                usuarioRepository.DbContext.CommitTransaction();
                return Json("");
            }
            catch (PreconditionException)
            {
                return Json("Ha ocurrido un error en la aplicación. Por favor intente más tarde.");
            }
            catch (Exception)
            {
                return Json("El registro no pudo ser eliminado, posiblemente tenga relación con otra entidad.");
            }
        }

        /// <summary>
        /// Inicializar combos para usuarios
        /// </summary>
        /// <param name="usuario"></param>
        private void InicializarCombosUsuario(Usuario usuario)
        {
            IList<Idioma> IdiomaCombo = idiomaRepository.GetAll();
            ViewData["CodigoIdioma"] = new SelectList(IdiomaCombo, "Id", "Nombre", usuario.CodigoIdioma);

            IList<Pais> PaisCombo = paisRepository.GetAll();
            ViewData["CodigoPais"] = new SelectList(PaisCombo, "Id", "Nombre", usuario.CodigoPais);

            IList<TimeZoneZeus> timeZone = timeZoneRepository.GetAll();
            ViewData["ZonaHoraria"] = new SelectList(timeZone, "Id", "Nombre", usuario.ZonaHoraria);

            List<SelectListItem> distancia = new List<SelectListItem>()
            {
                new SelectListItem { Value = "1", Text = "Km" },
                new SelectListItem { Value = "2", Text = "Millas" }
            };

            ViewData["Distancia"] = new SelectList(distancia, "Value", "Text", usuario.Distancia);

            List<SelectListItem> velocidad = new List<SelectListItem>()
            {
                new SelectListItem { Value = "1", Text = "Kph" },
                new SelectListItem { Value = "2", Text = "Mph" }
            };

            ViewData["Velocidad"] = new SelectList(velocidad, "Value", "Text", usuario.Velocidad);

            List<SelectListItem> mapa = new List<SelectListItem>()
            {
                new SelectListItem { Value = "0", Text = "Mapas de Flash" },
                new SelectListItem { Value = "1", Text = "Google Maps" }
            };

            ViewData["Mapa"] = new SelectList(mapa, "Value", "Text", usuario.Mapa);
                        
            List<SelectListItem> rol = new List<SelectListItem>()
            {                   
                new SelectListItem { Value = "usuario", Text = "Usuario" }
            };

//<<<<<<< .mine
//            List<SelectListItem> rol = new List<SelectListItem>()
//            {
//                new SelectListItem { Value = "admin", Text = "Administrador" },
//                new SelectListItem { Value = "cliente", Text = "Cliente" },
//                new SelectListItem { Value = "usuario", Text = "Usuario" }
//            };

//            ViewData["Rol"] = new SelectList(rol, "Value", "Text", usuario.Rol);

//=======
            if (workingSession.Usuario.Rol.Equals("admin"))
            {
                rol.Add(new SelectListItem { Value = "cliente", Text = "Cliente" });
                rol.Add(new SelectListItem { Value = "admin", Text = "Administrador" });
            }

            ViewData["Rol"] = new SelectList(rol, "Value", "Text", usuario.Rol);

//>>>>>>> .r260
        }

        #endregion

        #region Perimetros

        /// <summary>
        /// Listar los perimetros.
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [Transaction, Authorize]
        public ActionResult Perimetros(int? id, int? clienteId, int? und)
        {
            if (!usuarioRepository.IsInRole(User.Identity.Name, "admin,cliente"))
                return RedirectToAction("NoAutorizado", "Shared");

            try
            {
                IList<Cliente> clientes = clienteRepository.GetAll();
                ViewData["Clientes"] = new SelectList(clientes, "Id", "Nombre", clienteId);

                IList<Unidad> unidades = new List<Unidad>();

                if (usuarioRepository.IsInRole(User.Identity.Name, "admin"))
                {
                    unidades = unidadRepository.GetByCliente(clienteId ?? clientes[0].Id);
                    ViewData["IsAdmin"] = true;
                }
                else
                {
                    unidades = unidadRepository.GetByUsuario(workingSession.Usuario.Id);
                    ViewData["IsAdmin"] = false;
                }

                Dictionary<string, object> filtro = new Dictionary<string, object>();
                
                List<int> unidadesID = new List<int>();

                // Validar que exista la Unidad
                if (und != null && (bool)ViewData["IsAdmin"] == false)
                {
                    unidades.ToList().ForEach(p => unidadesID.Add(p.Id));
                    Check.Require(unidadesID.Contains(und.Value), "No se puede proceder con el ID indicado");
                }

                ViewData["CodigoUnidad"] = new SelectList(unidades, "Id", "Nombre", und ?? 0);

                if (und != null)
                    filtro.Add("CodigoUnidad", und);
                else if (unidades.Count > 0)
                    filtro.Add("CodigoUnidad", unidades.FirstOrDefault().Id);

                filtro.Add("Tipo", 1);

                IList<Poligono> poligonos = poligonoRepository.FindAll(filtro);
                PagedList<Poligono> poligonosList = new PagedList<Poligono>(poligonos, id ?? 1, 10);

                return View(poligonosList);
            }
            catch (PreconditionException ex)
            {
                TempData["ErrorMessage"] = ex.Message;
                return RedirectToAction("Error", "Shared");
            }
            catch (SessionExpiredException)
            {
                TempData["ErrorMessage"] = "Sesión Expirada!";
                TempData["Expire"] = true;
                return RedirectToAction("Error", "Shared");
            }
            catch (Exception ex)
            {
                TempData["ErrorMessage"] = ex.Message;
                return RedirectToAction("Error", "Shared");
            }
        }
               
        
        [Transaction, HttpPost, Authorize]
        public ActionResult Perimetros(int? id, string nombreHidden, int undHidden, int? clienteHidden)
        {
            if (!usuarioRepository.IsInRole(User.Identity.Name, "admin,cliente"))
                return RedirectToAction("NoAutorizado", "Shared");

            try
            {
                Poligono poligono = new Poligono()
                {
                    Nombre = nombreHidden,
                    CodigoUnidad = undHidden,
                    LatCenter = Convert.ToDecimal(-0.19474946),
                    LngCenter = Convert.ToDecimal(-78.50551128),
                    UsuarioCreacion = workingSession.Usuario.Login,
                    Tipo = 1,
                    Zoom = 12
                };

                poligonoRepository.SaveOrUpdate(poligono);

                return RedirectToAction("Perimetros", new { clienteId = clienteHidden, und = undHidden });
            }
            catch (PreconditionException ex)
            {
                TempData["ErrorMessage"] = ex.Message;
                return RedirectToAction("Error", "Shared");
            }
            catch (SessionExpiredException)
            {
                TempData["ErrorMessage"] = "Sesión Expirada!";
                TempData["Expire"] = true;
                return RedirectToAction("Error", "Shared");
            }
            catch (Exception ex)
            {
                TempData["ErrorMessage"] = ex.Message;
                return RedirectToAction("Error", "Shared");
            }
        }

        /// <summary>
        /// Metodo Get para mostrar
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [Transaction, Authorize]
        public ActionResult NuevoPerimetro(int id)
        {
            try
            {
                if (!usuarioRepository.IsInRole(User.Identity.Name, "admin,cliente"))
                    return RedirectToAction("NoAutorizado", "Shared");

                Poligono poligono = poligonoRepository.Get(id);
                Check.Require(poligono != null, "No se pudo recuperar el poligono");

                return View(poligono);
            }
            catch (PreconditionException ex)
            {
                TempData["ErrorMessage"] = ex.Message;
                return RedirectToAction("Error", "Shared");
            }
            catch (SessionExpiredException)
            {
                TempData["ErrorMessage"] = "Sesión Expirada!";
                TempData["Expire"] = true;
                return RedirectToAction("Error", "Shared");
            }
            catch (Exception ex)
            {
                TempData["ErrorMessage"] = ex.Message;
                return RedirectToAction("Error", "Shared");
            }
        }

        

        /// <summary>
        /// Eliminar un Perimetro o Ruta. Invocado mediante AJAX
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [Transaction, HttpPost, Authorize]
        public ActionResult EliminarPoligono(int id)
        {
            if (!usuarioRepository.IsInRole(User.Identity.Name, "admin,cliente"))
                return RedirectToAction("NoAutorizado", "Shared");

            try
            {
                Poligono poligono = poligonoRepository.Get(id);
                poligonoRepository.Delete(poligono);
                poligonoRepository.DbContext.CommitTransaction();
                return Json("");
            }
            catch (PreconditionException)
            {
                return Json("Ha ocurrido un error en la aplicación. Por favor intente más tarde.");
            }
            catch (Exception)
            {
                return Json("El registro no pudo ser eliminado, posiblemente tenga relación con otra entidad.");
            }
        }

        /// <summary>
        /// Guardar los puntos del poligono
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [Transaction, Authorize, HttpPost]
        public ActionResult SavePoints(int id, string ptos, string zoom, string lat, string lng)
        {
            try
            {
                Poligono poligono = poligonoRepository.Get(id);
                Check.Require(poligono != null, "No se pudo recuperar el poligono");

                poligono.Zoom = Convert.ToInt16(zoom);
                poligono.LatCenter = Convert.ToDecimal(lat);
                poligono.LngCenter = Convert.ToDecimal(lng);

                poligonoRepository.DeleteDetalles(id);

                string nuevo = ptos.Replace("),(", ";").Replace("(", string.Empty).Replace(")", string.Empty);
                string[] puntos = nuevo.Split(';');

                foreach (var item in puntos)
                {
                    string[] ubicacion = item.Split(',');
                    PoligonoDetalle detalle = new PoligonoDetalle()
                    {
                        Latitud = Convert.ToDecimal(ubicacion[0]),
                        Longitud = Convert.ToDecimal(ubicacion[1])
                    };

                    poligono.AddDetalle(detalle);
                }

                poligonoRepository.SaveOrUpdate(poligono);
                return Json("");
            }
            catch (PreconditionException ex)
            {
                return Json(ex.Message);
            }
            catch (SessionExpiredException)
            {
                return Json("La sesión ha caducado");
            }
            catch (Exception ex)
            {
                return Json(ex.Message);
            }
        }

        /// <summary>
        /// Recuperar los puntos de un poligono
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [Transaction, Authorize, HttpPost]
        public ActionResult RetrievePoints(int id)
        {
            try
            {
                Poligono poligono = poligonoRepository.Get(id);
                Check.Require(poligono != null, "No se pudo recuperar el poligono");

                List<Posicion> posiciones = new List<Posicion>();

                poligono.Detalles.ToList().ForEach(p => posiciones.Add(new Posicion()
                {
                    Latitud = p.Latitud,
                    Longitud = p.Longitud,
                    Zoom = poligono.Zoom,
                    LatCenter = poligono.LatCenter,
                    LngCenter = poligono.LngCenter
                }));

                return Json(posiciones);
            }
            catch (PreconditionException ex)
            {
                return Json(ex.Message);
            }
            catch (SessionExpiredException)
            {
                return Json("La sesión ha caducado");
            }
            catch (Exception ex)
            {
                return Json(ex.Message);
            }
        }

        #endregion

        #region Rutas
        /// <summary>
        /// Listar los perimetros.
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [Transaction, Authorize]
        public ActionResult Rutas(int? id, int? clienteId, int? und)
        {
            if (!usuarioRepository.IsInRole(User.Identity.Name, "admin,cliente"))
                return RedirectToAction("NoAutorizado", "Shared");

            try
            {
                IList<Cliente> clientes = clienteRepository.GetAll();
                ViewData["Clientes"] = new SelectList(clientes, "Id", "Nombre", clienteId);

                IList<Unidad> unidades = new List<Unidad>();

                if (usuarioRepository.IsInRole(User.Identity.Name, "admin"))
                {
                    unidades = unidadRepository.GetByCliente(clienteId ?? clientes[0].Id);
                    ViewData["IsAdmin"] = true;
                }
                else
                {
                    unidades = unidadRepository.GetByUsuario(workingSession.Usuario.Id);
                    ViewData["IsAdmin"] = false;
                }

                Dictionary<string, object> filtro = new Dictionary<string, object>();

                List<int> unidadesID = new List<int>();

                // Validar que exista la Unidad
                if (und != null && (bool)ViewData["IsAdmin"] == false)
                {
                    unidades.ToList().ForEach(p => unidadesID.Add(p.Id));
                    Check.Require(unidadesID.Contains(und.Value), "No se puede proceder con el ID indicado");
                }

                ViewData["CodigoUnidad"] = new SelectList(unidades, "Id", "Nombre", und ?? 0);

                if (und != null)
                    filtro.Add("CodigoUnidad", und);
                else if (unidades.Count > 0)
                    filtro.Add("CodigoUnidad", unidades.FirstOrDefault().Id);

                filtro.Add("Tipo", 2);

                IList<Poligono> poligonos = poligonoRepository.FindAll(filtro);
                PagedList<Poligono> poligonosList = new PagedList<Poligono>(poligonos, id ?? 1, 10);

                return View(poligonosList);
            }
            catch (PreconditionException ex)
            {
                TempData["ErrorMessage"] = ex.Message;
                return RedirectToAction("Error", "Shared");
            }
            catch (SessionExpiredException)
            {
                TempData["ErrorMessage"] = "Sesión Expirada!";
                TempData["Expire"] = true;
                return RedirectToAction("Error", "Shared");
            }
            catch (Exception ex)
            {
                TempData["ErrorMessage"] = ex.Message;
                return RedirectToAction("Error", "Shared");
            }
        }

        /// <summary>
        /// Invocado mediante AJAX para crear el nombre del Perimetro
        /// </summary>
        /// <param name="id"></param>
        /// <param name="nombreHidden"></param>
        /// <returns></returns> 
        [Transaction, HttpPost, Authorize]
        public ActionResult Rutas(int? id, string nombreHidden, string undHidden, int? clienteHidden)
        {
            if (!usuarioRepository.IsInRole(User.Identity.Name, "admin,cliente"))
                return RedirectToAction("NoAutorizado", "Shared");

            try
            {
                Poligono poligono = new Poligono()
                {
                    Nombre = nombreHidden,
                    CodigoUnidad = Convert.ToInt32(undHidden),
                    LatCenter = Convert.ToDecimal(-0.19474946),
                    LngCenter = Convert.ToDecimal(-78.50551128),
                    UsuarioCreacion = workingSession.Usuario.Login,
                    Tipo = 2,
                    Zoom = 12
                };

                poligonoRepository.SaveOrUpdate(poligono);

                return RedirectToAction("Rutas", new { clienteId = clienteHidden, und = undHidden });
            }
            catch (PreconditionException ex)
            {
                TempData["ErrorMessage"] = ex.Message;
                return RedirectToAction("Error", "Shared");
            }
            catch (SessionExpiredException)
            {
                TempData["ErrorMessage"] = "Sesión Expirada!";
                TempData["Expire"] = true;
                return RedirectToAction("Error", "Shared");
            }
            catch (Exception ex)
            {
                TempData["ErrorMessage"] = ex.Message;
                return RedirectToAction("Error", "Shared");
            }
        }

        /// <summary>
        /// Metodo Get para mostrar la ruta
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [Transaction, Authorize]
        public ActionResult NuevaRuta(int id)
        {
            try
            {
                if (!usuarioRepository.IsInRole(User.Identity.Name, "admin,cliente"))
                    return RedirectToAction("NoAutorizado", "Shared");

                Poligono poligono = poligonoRepository.Get(id);
                Check.Require(poligono != null, "No se pudo recuperar el poligono");

                return View(poligono);
            }
            catch (PreconditionException ex)
            {
                TempData["ErrorMessage"] = ex.Message;
                return RedirectToAction("Error", "Shared");
            }
            catch (SessionExpiredException)
            {
                TempData["ErrorMessage"] = "Sesión Expirada!";
                TempData["Expire"] = true;
                return RedirectToAction("Error", "Shared");
            }
            catch (Exception ex)
            {
                TempData["ErrorMessage"] = ex.Message;
                return RedirectToAction("Error", "Shared");
            }
        }

        #endregion

    }
}
